package com.credit.mola.app.ui.permission

import android.content.SharedPreferences
import android.content.pm.PackageManager
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import com.google.gson.Gson
import com.google.gson.annotations.SerializedName
import java.io.Serializable
import androidx.core.content.edit
import com.credit.mola.app.ui.permission.PermitUtil.PermitManager.PermitItem
import java.util.concurrent.atomic.AtomicInteger

/**
 *【 权限工具 】
 *
 * 使用方法：
 *
 * 1- readPermitManager 读取缓存的权限状态
 *
 * 2- checkPermitOperated 判断权限是否操作过
 *
 * 3- onCreate里实例化 PermitHelper
 *
 * 4- watchPermitMark 标记要观察的权限
 * (permitFinalPassCb 会在标记的权限都通过或操作过后触发)
 *
 * 5- checkWatchPermit 可主动检查观察的权限的状态
 *
 * 6- grantPermit 或 denyPermit，使用 PermitHelper 的回调来判断后续处理逻辑
 *
 * 7- writePermitManager 记得最后保存权限的状态
 *
 * 8- 想重新判断所有权限？用 resetPermitOperated 来重置权限
 *
 * X- 可用 gTargetPermitByXXX 来获取某个权限的状态
 */
object PermitUtil {

    // ========== 权限核心数据 ==========

    // SharedPreference管理标志
    private const val SP_PERMIT_MGR = "sp_permit_mgr" // test

    // 权限标志
    const val PERMIT_MARK_SMS = "SMS"       // 权限：短信
    const val PERMIT_MARK_CAMERA = "CAMERA" // 权限：相机
    const val PERMIT_MARK_APP = "APP"       // 权限：应用列表
    const val PERMIT_MARK_PHONE = "PHONE"   // 权限：设备信息

    // 权限值
    const val PERMIT_VALUE_SMS = "android.permission.READ_SMS"
    const val PERMIT_VALUE_CAMERA = "android.permission.CAMERA"

    // 权限状态值
    const val PERMIT_STATUS_DEFAULT = 0 // 权限状态：默认
    const val PERMIT_STATUS_AGREE = 1   // 权限状态：授予
    const val PERMIT_STATUS_DENY = -1   // 权限状态：拒绝

    /** 权限管理器 */
    class PermitManager : Serializable {
        /** 权限：短信 */
        @SerializedName("permit_sms")
        var permitSms = PermitItem(
            mark = PERMIT_MARK_SMS,
            valueLst = listOf(PERMIT_VALUE_SMS),
            content = "This is SMS content",
            grant = AtomicInteger(PERMIT_STATUS_DEFAULT),
            sysDeny = false
        )

        /** 权限：相机 */
        @SerializedName("permit_camera")
        var permitCamera = PermitItem(
            mark = PERMIT_MARK_CAMERA,
            valueLst = listOf(PERMIT_VALUE_CAMERA),
            content = "This is CAMERA content",
            grant = AtomicInteger(PERMIT_STATUS_DEFAULT),
            sysDeny = false
        )

        /** 权限：应用列表 */
        @SerializedName("permit_app")
        var permitApp = PermitItem(
            mark = PERMIT_MARK_APP,
            valueLst = emptyList(),
            content = "This is APP_LIST content",
            grant = AtomicInteger(PERMIT_STATUS_DEFAULT),
            sysDeny = false
        )

        /** 权限：设备信息 */
        @SerializedName("permit_phone")
        var permitPhone = PermitItem(
            mark = PERMIT_MARK_PHONE,
            valueLst = emptyList(),
            content = "This is PHONE_STATE content",
            grant = AtomicInteger(PERMIT_STATUS_DEFAULT),
            sysDeny = false
        )

        /** 权限对象 */
        data class PermitItem(
            /**
             * 权限标志
             *
             * @see PERMIT_MARK_SMS
             */
            @SerializedName("mark")
            var mark: String,

            /**
             * 权限值（假权限值为空）
             *
             * @see PERMIT_VALUE_SMS
             */
            @SerializedName("value_lst")
            var valueLst: List<String>,

            /** 权限文案 */
            @SerializedName("content")
            var content: String,

            /**
             * 授予状态
             *
             * @see PERMIT_STATUS_DEFAULT
             */
            @SerializedName("grant")
            var grant: AtomicInteger,

            /** 系统权限是否拒绝 */
            @SerializedName("sys_deny")
            var sysDeny: Boolean
        ) : Serializable
    }

    /** 【核心】：权限管理器 */
    private var permitManager = PermitManager()


    /** 【读取】：权限管理器（权限执行工具初始化时调用） */
    fun readPermitManager(sp: SharedPreferences) {
        // 读取
        var readResult = ""
        try {
            readResult = sp.getString(SP_PERMIT_MGR, "") ?: ""
        } catch (e: Exception) {
            e.printStackTrace()
        }
        if (readResult.isBlank()) return
        // 解析
        permitManager =
            Gson().fromJson(readResult, PermitManager::class.java) ?: PermitManager()
    }

    /** 【写入】：权限管理器（权限执行工具结束时调用） */
    fun writePermitManager(sp: SharedPreferences) {
        // 编译
        val writeContent = Gson().toJson(permitManager, PermitManager::class.java)
        // 写入
        sp.edit {
            putString(SP_PERMIT_MGR, writeContent)
        }
    }

    /**
     * 【查询】：根据【权限标记】获取满足的权限
     * - 获取后可以直接操作权限的状态值
     *
     * @param permitMark 权限标记
     * @see PermitUtil.PERMIT_MARK_SMS
     */
    fun gTargetPermitByMark(permitMark: String): PermitItem? {
        return when (permitMark) {
            PERMIT_MARK_SMS -> permitManager.permitSms
            PERMIT_MARK_CAMERA -> permitManager.permitCamera
            PERMIT_MARK_APP -> permitManager.permitApp
            PERMIT_MARK_PHONE -> permitManager.permitPhone
            else -> null
        }
    }

    /**
     * 【查询】：根据【权限值】获取满足的权限
     * - 获取后可以直接操作权限的状态值
     *
     * @param permitValue 权限值
     * @see PermitUtil.PERMIT_VALUE_SMS
     */
    fun gTargetPermitByValue(permitValue: String): PermitItem? {
        return when (permitValue) {
            PERMIT_VALUE_SMS -> permitManager.permitSms
            PERMIT_VALUE_CAMERA -> permitManager.permitCamera
            else -> null
        }
    }

    /**
     * 【判断】：目标权限【是否操作过】
     *
     * @param permitMark 权限标记
     * @param allOperated 是否需要全部操作过，默认需要全部操作
     * @see PermitUtil.PERMIT_MARK_SMS
     */
    fun checkPermitOperated(vararg permitMark: String,allOperated: Boolean? = true): Boolean {
        //目标权限，需要全部操作过
        if (allOperated == true){
            var isAllOperated = true
            for (mark in permitMark){
                gTargetPermitByMark(mark)?.let {
                    if (it.grant.get() == PERMIT_STATUS_DEFAULT){
                        isAllOperated = false
                    }
                }
                if (!isAllOperated) break
            }
            return isAllOperated
        }

        //目标权限，只要操作过任意一个，即视为操作过
        var isOperated = false
        for (mark in permitMark){
            gTargetPermitByMark(mark)?.let {
                if (it.grant.get() != PERMIT_STATUS_DEFAULT){
                    isOperated = true
                }
            }
            if (isOperated) break
        }
        return isOperated
    }

    /**
     * 【判断】：目标权限【是否全部同意】
     *
     * @param permitMark 权限标记
     * @see PermitUtil.PERMIT_MARK_SMS
     */
    fun checkPermitAgreed(vararg permitMark: String): Boolean {
        // 目标权限是否同意状态
        var allAgreed = true
        for (mark in permitMark) {
            gTargetPermitByMark(mark)?.let {
                if (it.grant.get() != PERMIT_STATUS_AGREE)
                    allAgreed = false
            }
            if (!allAgreed) break
        }
        return allAgreed
    }

    /**
     * 重置目标权限为【未操作过】
     *
     * @param permitMark 权限标记
     * @see PermitUtil.PERMIT_MARK_SMS
     */
    fun resetPermitOperated(vararg permitMark: String) {
        for (mark in permitMark) {
            gTargetPermitByMark(mark)?.grant?.set(PERMIT_STATUS_DEFAULT)
        }
    }

    /** 重置所有权限为【未操作过】 */
    fun resetAllPermitOperated(sp: SharedPreferences) {
        resetPermitOperated(
            PERMIT_MARK_SMS, PERMIT_MARK_CAMERA, PERMIT_MARK_APP, PERMIT_MARK_PHONE
        )
        writePermitManager(sp)
    }

    // ========== 权限判断 ==========

    /**
     * 权限执行工具（注意：需要在onCreate初始化）
     *
     * @param needAllPermit 是否需要所有权限
     * @param permitUpdateCb 权限状态更新回调
     * @param permitPointCb 权限埋点回调
     * @param permitFinalPassCb 权限最终检查通过回调
     * @param permitFinalFailCb 权限最终检查失败回调
     * @param goSettingCb 去设置页开启权限回调
     */
    class PermitHelper(
        private val activity: AppCompatActivity,
        private val needAllPermit: Boolean = false,
        private val permitUpdateCb: (permitItem: PermitItem) -> Unit = { _ -> },
        private val permitPointCb: (permitMark: String, permitGrant: Boolean) -> Unit = { _, _ -> },
        private val permitFinalPassCb: () -> Unit = {},
        private val permitFinalFailCb: () -> Unit = {},
        private val goSettingCb: (permitItem: PermitItem) -> Unit = {}
    ) {
        // 权限申请结果监听
        private val permitRegister =
            activity.registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { resultMap ->
                // 进行申请的权限名
                val permitValueKeys = resultMap.keys
                // 权限检查失败
                var isCheckFail = false

                // 检查申请后的权限
                for (valueKey in permitValueKeys) {
                    // 权限授予
                    if (resultMap[valueKey] == true) {
                        gTargetPermitByValue(valueKey)?.let {
                            it.grant.set(PERMIT_STATUS_AGREE)
                            permitUpdateCb.invoke(it) // 状态更新回调
                        }
                    }
                    // 权限拒绝
                    else {
                        gTargetPermitByValue(valueKey)?.let {
                            it.sysDeny = true // 只有此处可以更新sysDeny
                            permitPointCb.invoke(it.mark, false) // 状态埋点回调（情况：先同意后拒绝）
                            // 根据权限要求程度决定后续逻辑
                            if (needAllPermit) {
                                // 不视作操作完成
                                isCheckFail = true
                            }
                                // 视作操作完成：已拒绝
                                it.grant.set(PERMIT_STATUS_DENY)
                                permitUpdateCb.invoke(it) // 状态更新回调

                        }
                    }
                }
                // 权限检查是否失败
                if (isCheckFail) {
                    permitFinalFailCb.invoke()
                } else {
                    checkWatchPermit()
                }
            }


        // ========== 权限观察 ==========

        /** 处于观察状态的权限标志 */
        private var watchPermitMarkLst: List<String> = emptyList()
        private val watchPermitLock: String = "WATCH_PERMIT_LOCK" // 锁

        /**
         * 【观察】：意向观察状态的权限
         *
         * @param permitMarkLst 权限标志列表
         * @see PermitUtil.PERMIT_MARK_SMS
         */
        fun watchPermitMark(permitMarkLst: List<String>) {
            synchronized(watchPermitLock) {
                watchPermitMarkLst = permitMarkLst
            }
        }

        /** 检查正在观察的权限的状态 */
        fun checkWatchPermit() {
            synchronized(watchPermitLock) {
                var isCheckSuccess = true
                for (permitMark in watchPermitMarkLst) {
                    gTargetPermitByMark(permitMark)?.let {
                        // 假权限-是否未操作
                        if (it.valueLst.isEmpty()) {
                            if (it.grant.get() == PERMIT_STATUS_DEFAULT)
                                isCheckSuccess = false
                        }
                        // 真权限-是否同意
                        else {
                            // 问询系统
                            if (isPermitGrant(it.valueLst))
                                it.grant.set(PERMIT_STATUS_AGREE)
                            if (it.grant.get() != PERMIT_STATUS_AGREE)
                                isCheckSuccess = false
                        }
                    }
                    if (!isCheckSuccess) break
                }
                if (isCheckSuccess)
                    permitFinalPassCb.invoke()
            }
        }

        // ========== 权限操作 ==========

        /**
         * 【执行】：意向授予权限
         *
         * @param permitMark 权限标志
         * @see PermitUtil.PERMIT_MARK_SMS
         */
        fun grantPermit(permitMark: String) {
            gTargetPermitByMark(permitMark)?.let {
                permitPointCb.invoke(it.mark, true) // 状态埋点回调
                // 假权限
                if (it.valueLst.isEmpty()) {
                    it.grant.set(PERMIT_STATUS_AGREE)
                    permitUpdateCb.invoke(it) // 状态更新回调
                    checkWatchPermit()
                }
                // 真权限-权限已授予
                else if (isPermitGrant(it.valueLst)) {
                    it.grant.set(PERMIT_STATUS_AGREE)
                    permitUpdateCb.invoke(it) // 状态更新回调
                    checkWatchPermit()
                }
                // 真权限-权限未授予&系统弹窗已拒绝
                else if (it.sysDeny) {
                    goSettingCb.invoke(it)
                }
                // 真权限-权限未授予&系统弹窗未拒绝
                else {
                    permitRegister.launch(it.valueLst.toTypedArray())
                }
            }
        }

        /**
         * 【执行】：意向拒绝权限
         *
         * @param permitMark 权限标志
         * @see PermitUtil.PERMIT_MARK_SMS
         */
        fun denyPermit(permitMark: String) {
            gTargetPermitByMark(permitMark)?.let {
                permitPointCb.invoke(it.mark, false) // 状态埋点回调
                // 假权限
                if (it.valueLst.isEmpty()) {
                    it.grant.set(PERMIT_STATUS_DENY)
                    permitUpdateCb.invoke(it) // 状态更新回调
                    checkWatchPermit()
                }
                // 真权限-需要所有权限
                else {
                    if (needAllPermit) {
                        permitFinalFailCb.invoke()
                    }
                    it.grant.set(PERMIT_STATUS_DENY)
                    permitUpdateCb.invoke(it) // 状态更新回调
                    checkWatchPermit()
                }
            }
        }

        // ========== 内部工具 ==========

        /** 系统是否授予权限 */
        private fun isPermitGrant(permitValueLst: List<String>): Boolean {
            var grantFinal = true
            for (permitValue in permitValueLst)
                if (ContextCompat.checkSelfPermission(activity, permitValue) !=
                    PackageManager.PERMISSION_GRANTED
                ) {
                    grantFinal = false
                    break
                }
            return grantFinal
        }
    }
}